home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockBlogService.js < prev    next >
Text File  |  2007-10-18  |  47KB  |  1,467 lines

  1. // BEGIN FLOCK GPL
  2. // 
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. // 
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. // 
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. // 
  15. // END FLOCK GPL
  16.  
  17. // Constants
  18. const Cc = Components.classes;
  19. const Ci = Components.interfaces;
  20. const Cr = Components.results;
  21.  
  22. const EDITOR_URL = "chrome://flock/content/blog/editor.xul";
  23.  
  24. const DEBUG = false;                // set to false to suppress debug messages
  25. const FLOCK_BLOG_CID                = Components.ID('{70b6c92b-8f34-4d1c-9057-e03e10770b96}');
  26.  
  27. const OLD_SHELF_RDF_FILE            = "flock_shelf.rdf";
  28. const OLD_BLOG_RDF_FILE             = "flock_blog.rdf";
  29. const OLD_BLOG_RDF_FILE_RELIC       = "flock_blog_old.rdf";
  30.  
  31. const FLOCK_BLOG_CONTRACTID         = '@flock.com/flock-blog;1';
  32.  
  33. const FLOCK_DRAFTS_ROOT             = 'http://flock.com/rdf#DraftsRoot';
  34. const FLOCK_RECOVERY_ROOT           = 'http://flock.com/rdf#RecoveryRoot';
  35. const FLOCK_UNPUBLISHED_ROOT        = 'http://flock.com/rdf#UnpublishedRoot';
  36.  
  37. const BLOG_CONTENT_FILE      = 'blogdrafts.sqlite';
  38.  
  39. var gBlogStorage   = null;
  40.  
  41. function BlogAPIDetector() {
  42.   this.mReq = null;
  43.   this.mTitle = null;
  44. }
  45.  
  46.  
  47. BlogAPIDetector.prototype.getTitle =
  48. function() {
  49.   return this.mTitle;
  50. }
  51.  
  52.  
  53. BlogAPIDetector.prototype.doRequest =
  54. function(listener, url, processor) {
  55.   var inst = this;
  56.   var rootUrl = 'http://'+url.split('/')[2];
  57.   this.mReq = Cc['@mozilla.org/xmlextras/xmlhttprequest;1'].createInstance(Ci.nsIXMLHttpRequest);
  58.   this.mReq.onreadystatechange = function (aEvt) {
  59.     try {
  60.       if(inst.mReq.readyState == 4) {
  61.         if(inst.mReq.status == 200) {
  62.           // debug(inst.mReq.responseText + "\n");
  63.           try {
  64.             processor(listener, rootUrl, inst);
  65.           }
  66.           catch(e) {
  67.             debug("Error "+e+" "+e.fileName+" line "+e.lineNumber+"\n");
  68.             listener.onError(e);
  69.           }
  70.         }
  71.         else {
  72.           debug("\nRESPONSE\n" + inst.mReq.responseText);
  73.           listener.onError(inst.mReq.status);
  74.         }
  75.       }
  76.     }
  77.     catch(e) {
  78.       debug("Error "+e+" "+e.fileName+" line "+e.lineNumber+"\n");
  79.       listener.onError(-1);
  80.     }
  81.   }
  82.   this.mReq.open('GET', url, true);
  83.   this.mReq.send(null); 
  84. }
  85.  
  86.  
  87. BlogAPIDetector.prototype.onHomePage =
  88. function (listener, rootUrl, inst)
  89. {
  90.   // The following code is to clean up dirty html to make it parser
  91.   // friendly
  92.  
  93.   var req = inst.mReq;          
  94.   var text = req.responseText;
  95.   text = text.replace(/[\r\n]/g,"");
  96.        
  97.   if(text.match(/<title.*>(.+?)</)) {
  98.     inst.mTitle = RegExp.$1;
  99.   }
  100.  
  101.   var linkObj = function () {
  102.   }
  103.  
  104.   linkObj.prototype = {
  105.     href:null,
  106.     rel:null,
  107.     type:null,
  108.     title:null,
  109.     QueryInterface: function (iid) {
  110.       if (!iid.equals(Ci.flockIBlogLink)) 
  111.           throw Cr.NS_ERROR_NO_INTERFACE;
  112.       return this;
  113.     }
  114.   }
  115.  
  116.   var linklist = new Array();
  117.  
  118.   var R = /<link.+?>/g;
  119.   var ar = R.exec(text);
  120.   while(ar) {
  121.     var cur = ar[0] + "";
  122.     var link = new linkObj();
  123.     if(cur.match(/href=\"(.+?)\"/)) {
  124.       link.href = RegExp.$1;
  125.     }
  126.     if(cur.match(/rel=\"(.+?)\"/)) {
  127.       link.rel = RegExp.$1;
  128.     }
  129.     if(cur.match(/title=\"(.+?)\"/)) {
  130.       link.title = RegExp.$1;
  131.     }
  132.     if(cur.match(/type=\"(.+?)\"/)) {
  133.       link.type = RegExp.$1;
  134.     }
  135.     linklist.push(link);
  136.     ar = R.exec(text);
  137.   }
  138.  
  139.   var blogService = Cc[FLOCK_BLOG_CONTRACTID].getService(Ci.flockIBlogService);
  140.   var accountList = new Array();
  141.   var webServices = blogService.services;
  142.   while(webServices.hasMoreElements()) {
  143.     var service = webServices.getNext();
  144.     service.QueryInterface(Ci.flockICustomBlogWebService);
  145.     // Clone the array because our simpleEnumerator destroy it
  146.     var linklistClone = new Array();
  147.     for (i = 0; i < linklist.length; i++)
  148.       linklistClone[i] = linklist[i];
  149.     var account = service.detectAccount(rootUrl, simpleEnumerator(linklistClone));
  150.     if (account) {
  151.       debug(" ==> we found support for "+service.shortName+"\n");
  152.       accountList.push(account);
  153.     }
  154.     else {
  155.       debug(" xxx "+service.shortName+" support not found for this blog\n");
  156.     }
  157.   }
  158.  
  159.   // Let's look in the RSD before we use something else
  160.   var rsd = null;
  161.   for (i = 0; i < linklist.length; i++) {
  162.     var link = linklist[i];
  163.     if (link.title=="RSD" || link.type=="application/rsd+xml") {
  164.       debug("We found a RSD!\n"+link.href+"\n");
  165.       rsd = link;
  166.     }
  167.   }
  168.   if (rsd) {
  169.     var xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance (Ci.nsIXMLHttpRequest);
  170.     xhr.open ('GET', rsd.href, true);
  171.  
  172.     xhr.onreadystatechange = function (aEvent) {
  173.       if (xhr.readyState == 4) {
  174.         if (xhr.status != 200) {
  175.           // Error
  176.           listener.onResult(null);
  177.           return;
  178.         }
  179.         var dom = xhr.responseXML;
  180.         if(!dom) {
  181.           // FIXME: Parse responseText is responseXML is not present (= bad XML)
  182.           //var parser = new DOMParser();
  183.           //dom = parser.parseFromString(req.responseText,"text/xml");
  184.           debug("No dom!!\n");
  185.           listener.onResult(null);
  186.           return;
  187.         }
  188.         var apis = dom.getElementsByTagName("api");
  189.         var prefApi = null;
  190.         var apiList = [];
  191.         for(var i=0;i<apis.length;++i) {
  192.           var api = {
  193.             api: apis[i].getAttribute("name").toLowerCase().replace(/\s/g,""),
  194.             apiLink: apis[i].getAttribute("apiLink"),
  195.             preferred: apis[i].getAttribute("preferred").toLowerCase(),
  196.             blogid: apis[i].getAttribute("blogID")
  197.           }
  198.           apiList.push(api);
  199.           if (api.preferred == 'true')
  200.             prefApi = api;
  201.         }
  202.         if (prefApi) {
  203.           var svc = blogService.getAPIFromShortname(prefApi.api);
  204.           debug("prefApi: looking for the service having shortname {"+prefApi.api+"}\n");
  205.           if (svc) {
  206.             listener.onResult(prefApi);
  207.             return;
  208.           }
  209.         }
  210.         while (apiList.length > 0) {
  211.           var currentApi = apiList.shift();
  212.           debug("looking for the service having shortname {"+currentApi.api+"}\n");
  213.           var svc = blogService.getAPIFromShortname(currentApi.api);
  214.           if (svc) {
  215.             listener.onResult(currentApi);
  216.             return;
  217.           }
  218.         }
  219.         // We couldn't find any supported API in the RSD. Loop in what we had before?
  220.         listener.onResult(null);
  221.       }
  222.     }
  223.     xhr.send (null);
  224.   }
  225.   else { // No RSD
  226.     if (accountList.length > 0) {
  227.       // Return the first account in the list
  228.       listener.onResult(accountList[0]); 
  229.     }
  230.     else {
  231.       listener.onResult(null); 
  232.     }
  233.   }
  234. }
  235.  
  236.  
  237. BlogAPIDetector.prototype.detect =
  238. function(listener, url)
  239. {
  240.   this.doRequest(listener, url, this.onHomePage);
  241. }
  242.  
  243. function BlogDraft () {
  244. }
  245.  
  246. BlogDraft.prototype = {
  247.   getInterfaces: function (count) {
  248.     var interfaceList = [Components.interfaces.flockIBlogDraft, Components.interfaces.nsIClassInfo];
  249.     count.value = interfaceList.length;
  250.     return interfaceList;
  251.   },
  252.   QueryInterface: function (iid) {
  253.     if (!iid.equals(Components.interfaces.flockIBlogDraft))
  254.       throw Components.results.NS_ERROR_NO_INTERFACE;
  255.     return this;
  256.   },
  257.   getHelperForLanguage: function (count) {return null;}
  258. }
  259.  
  260.  
  261. function createStatement(dbconn, sql) {
  262.   var stmt = dbconn.createStatement(sql);
  263.   var wrapper = Cc["@mozilla.org/storage/statement-wrapper;1"]
  264.     .createInstance(Ci.mozIStorageStatementWrapper);
  265.  
  266.   wrapper.initialize(stmt);
  267.   return wrapper;
  268. }
  269.  
  270. function BlogStorage() {
  271.   var dbfile = Cc['@mozilla.org/file/directory_service;1']
  272.     .getService(Ci.nsIProperties).get('ProfD', Ci.nsIFile);
  273.   dbfile.append(BLOG_CONTENT_FILE);
  274.  
  275.   var storageService = Cc['@mozilla.org/storage/service;1']
  276.     .getService(Ci.mozIStorageService);
  277.   this._DBConn = storageService.openDatabase(dbfile);
  278.  
  279.   var drafts_schema = "id INTEGER PRIMARY KEY, lastupdate INTEGER, title STRING, " +
  280.                       "content STRING, tags STRING, blog STRING DEFAULT ''";
  281.  
  282.   var recovery_schema = 'id INTEGER PRIMARY KEY, lastupdate INTEGER, title STRING, ' +
  283.                         'content STRING, tags STRING';
  284.  
  285.   try {
  286.     this._DBConn.createTable('drafts', drafts_schema);
  287.     this._DBConn.createTable('recovery', recovery_schema);
  288.   }
  289.   catch (e) { }
  290.  
  291.   this._getDraftsFrom = createStatement(this._DBConn,
  292.     'SELECT * FROM drafts WHERE blog = :blog');
  293.   this._getDraft = createStatement(this._DBConn,
  294.     'SELECT * FROM drafts WHERE id = :id');
  295.   this._replaceDraft = createStatement(this._DBConn,
  296.     'REPLACE INTO drafts (id, lastupdate, title, content, tags) ' +
  297.     'VALUES (:id, :lastupdate, :title, :content, :tags)');
  298.   this._removeDraft = createStatement(this._DBConn,
  299.     'DELETE FROM drafts where id = :id');
  300.   this._setDraftBlog = createStatement(this._DBConn,
  301.     'UPDATE drafts SET blog=:blog WHERE id=:id');
  302.  
  303.   this._replaceRecovery = createStatement(this._DBConn,
  304.     'REPLACE INTO recovery (id, lastupdate, title, content, tags) ' +
  305.     'VALUES (:id, :lastupdate, :title, :content, :tags)');
  306.   this._removeRecovery = createStatement(this._DBConn,
  307.     'DELETE FROM recovery where id = :id');
  308.   this._getAllRecovery = createStatement(this._DBConn,
  309.     'SELECT * FROM recovery');
  310.   this._emptyRecovery = createStatement(this._DBConn,
  311.     'DELETE FROM recovery');
  312. }
  313.  
  314. BlogStorage.prototype = {
  315.   deleteDraft: function BS_deleteDraft(id) {
  316.     this._removeDraft.params.id = id;
  317.     this._removeDraft.step();
  318.     this._removeDraft.reset();
  319.   },
  320.   deleteRecovery: function BS_deleteRecovery(id) {
  321.     this._removeRecovery.params.id = id;
  322.     this._removeRecovery.step();
  323.     this._removeRecovery.reset();
  324.   },
  325.   emptyRecovery: function BS_emptyRecovery() {
  326.     this._emptyRecovery.step();
  327.     this._emptyRecovery.reset();
  328.   },
  329.   saveDraft: function FS_saveDraft(id, lastupdate, title, content, tags) {
  330.     var pp = this._replaceDraft.params;
  331.     pp.id = id;
  332.     pp.lastupdate = lastupdate;
  333.     pp.title = title;
  334.     pp.content = content;
  335.     pp.tags = tags;
  336.     this._replaceDraft.step();
  337.     this._replaceDraft.reset();
  338.   },
  339.   setDraftBlog: function FS_setDraftBlog(id, blog) {
  340.     var pp = this._setDraftBlog.params;
  341.     pp.id = id;
  342.     pp.blog = blog;
  343.     this._setDraftBlog.step();
  344.     this._setDraftBlog.reset();
  345.   },
  346.   saveRecovery: function FS_saveRecovery(id, lastupdate, title, content, tags) {
  347.     var pp = this._replaceRecovery.params;
  348.     pp.id = id;
  349.     pp.lastupdate = lastupdate;
  350.     pp.title = title;
  351.     pp.content = content;
  352.     pp.tags = tags;
  353.     this._replaceRecovery.step();
  354.     this._replaceRecovery.reset();
  355.   },
  356.   getDraftsFrom: function FS_getDraftsFrom(blog) {
  357.     var result = [];
  358.     this._getDraftsFrom.reset();
  359.     var pp = this._getDraftsFrom.params;
  360.   
  361.     pp.blog = blog;
  362.     while (this._getDraftsFrom.step()) {
  363.       var draft = new BlogDraft();
  364.       draft.id = this._getDraftsFrom.row['id'];
  365.       draft.lastupdate = this._getDraftsFrom.row['lastupdate'];
  366.       draft.title = this._getDraftsFrom.row['title'];
  367.       draft.content = this._getDraftsFrom.row['content'];
  368.       draft.tags = this._getDraftsFrom.row['tags'];
  369.       result.push(draft);
  370.     }
  371.     this._getDraftsFrom.reset();
  372.  
  373.     return result;
  374.   },
  375.   getAllRecovery: function FS_getAllRecovery() {
  376.     var result = [];
  377.     this._getAllRecovery.reset();
  378.     while (this._getAllRecovery.step()) {
  379.       var recovery = new BlogDraft();
  380.       recovery.id = this._getAllRecovery.row['id'];
  381.       recovery.lastupdate = this._getAllRecovery.row['lastupdate'];
  382.       recovery.title = this._getAllRecovery.row['title'];
  383.       recovery.content = this._getAllRecovery.row['content'];
  384.       recovery.tags = this._getAllRecovery.row['tags'];
  385.       result.push(recovery);
  386.     }
  387.     this._getAllRecovery.reset();
  388.  
  389.     return result;
  390.   },
  391.   getDraft: function FS_getDraft(draftid) {
  392.     var draft = null;
  393.  
  394.     this._getDraft.reset();
  395.     this._getDraft.params.id = draftid;
  396.  
  397.     if (this._getDraft.step()) {
  398.       draft = new BlogDraft();
  399.       draft.id = this._getDraft.row['id'];
  400.       draft.lastupdate = this._getDraft.row['lastupdate'];
  401.       draft.title = this._getDraft.row['title'];
  402.       draft.content = this._getDraft.row['content'];
  403.       draft.tags = this._getDraft.row['tags'];
  404.     }
  405.     
  406.     this._getDraft.reset();
  407.     return draft;
  408.   },
  409.   beginTransaction: function FS_beginTransation() {
  410.     this._DBConn.beginTransaction();
  411.   },
  412.   commitTransaction: function FS_commitTransation() {
  413.     this._DBConn.commitTransaction();
  414.   },
  415.   rollbackTransaction: function FS_rollbackTransation() {
  416.     this._DBConn.rollbackTransaction();
  417.   },
  418.   _getData: function FS__getData(id, stmt, field) {
  419.     stmt.reset();
  420.     stmt.params.id = id;
  421.  
  422.     var data = null;
  423.     if (stmt.step())
  424.       data = stmt.row[field];
  425.     stmt.reset();
  426.     return data;
  427.   }
  428. }
  429.  
  430.  
  431. function flockBlogService() {
  432.   // For an observer on flock-data-ready for import
  433.   var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
  434.   obs.addObserver(this, 'flock-data-ready', false);
  435.  
  436.   this.acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  437.  
  438.   this.initialized = false;
  439. }
  440.  
  441.  
  442. flockBlogService.prototype.init =
  443. function()
  444. {
  445.   if (this.initialized)
  446.     return;
  447.  
  448.   gBlogStorage = new BlogStorage();
  449.  
  450.   this._coop = Cc["@flock.com/singleton;1"]
  451.                .getService(Ci.flockISingleton)
  452.                .getSingleton("chrome://flock/content/common/load-faves-coop.js")
  453.                .wrappedJSObject;
  454.  
  455.   if (!this.needsMigration(null)) {
  456.     var prefsService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
  457.     var blogBranch = prefsService.getBranch("flock.blog.");
  458.     var mozstorage = false;
  459.     try {
  460.       mozstorage = blogBranch.getBoolPref("mozstorage");
  461.     } catch(e) { /* The pref is not set yet */ }
  462.     if (!mozstorage) {
  463.       var draftsRoot = this._coop.get(FLOCK_DRAFTS_ROOT);
  464.       if (draftsRoot) {
  465.         // Migrate from RDF to mozstorage (0.9.0 => 0.9.1)
  466.         var folders = draftsRoot.children.enumerate();        
  467.         while (folders.hasMoreElements()) {
  468.           var folder = folders.getNext();
  469.           var blogid = "";
  470.           if (!folder.id().match('UnpublishedRoot')) {
  471.             blogid = folder.id().split(":folder:").pop();
  472.           }
  473.           var drafts = folder.children.enumerate();
  474.           while (drafts.hasMoreElements()) {
  475.             var draft = drafts.getNext();
  476.             // Add the draft to BlogStorage
  477.             var draftid = this.saveDraft(null, draft.name, draft.content, draft.tags);
  478.             this.moveTo(draftid, blogid);
  479.             // Then remove it from RDF
  480.             folder.children.remove(draft);
  481.             draft.destroy();
  482.           }
  483.           draftsRoot.children.remove(folder);
  484.           folder.destroy();
  485.         }
  486.         draftsRoot.destroy();
  487.       }
  488.       blogBranch.setBoolPref("mozstorage", true);
  489.     }
  490.   }
  491.  
  492.   this.mName2ServiceMap = {};
  493.   this.mService2NameMap = {};
  494.  
  495.   // Logger
  496.   this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
  497.   this.logger.init("blogservice");
  498.  
  499.   // Add Technorati.com on first run
  500.   var prefsService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
  501.   var blogBranch = prefsService.getBranch("flock.blog");
  502.   try {
  503.     var firstRun = blogBranch.getIntPref("firstRun");
  504.   } catch(e) {}
  505.   if (!firstRun) {
  506.     // TODO
  507.     //this.addNotification("http://www.technorati.com")
  508.     //blogBranch.setIntPref("firstRun", 1);
  509.     //blogBranch.setBoolPref("notify", true);
  510.   }
  511.  
  512.   // Search for registered blog web services
  513.   var catmgr = Cc["@mozilla.org/categorymanager;1"]
  514.       .getService (Ci.nsICategoryManager);
  515.   var enum_ = catmgr.enumerateCategory("flockICustomBlogWebService");
  516.   while(enum_.hasMoreElements()) {
  517.     var obj = enum_.getNext();
  518.     supportsString = obj.QueryInterface(Ci.nsISupportsCString);
  519.     var shortName = supportsString.toString();
  520.     var cid = catmgr.getCategoryEntry("flockICustomBlogWebService", shortName); 
  521.     var svc = Cc[cid].getService(Ci.flockICustomBlogWebService);
  522.     this.registerAPI(svc, shortName);
  523.   }
  524.  
  525.   this.initialized = true;
  526. }
  527.  
  528. //flockIMigratable
  529. flockBlogService.prototype.__defineGetter__("migrationName",
  530. function flockBlogService_getter_migrationName() {
  531.   return "Blogging Accounts";
  532. });
  533.  
  534. flockBlogService.prototype.needsMigration =
  535. function (oldVersion)
  536. {
  537.   var oldShelfFile = Cc["@mozilla.org/file/directory_service;1"] 
  538.                        .getService(Ci.nsIProperties)
  539.                        .get("ProfD", Ci.nsIFile);
  540.   oldShelfFile.append(OLD_SHELF_RDF_FILE);
  541.  
  542.   var oldBlogFile = Cc["@mozilla.org/file/directory_service;1"] 
  543.                        .getService(Ci.nsIProperties)
  544.                        .get("ProfD", Ci.nsIFile);
  545.   oldBlogFile.append(OLD_BLOG_RDF_FILE);
  546.  
  547.   var relicBlogFile = Cc["@mozilla.org/file/directory_service;1"] 
  548.                        .getService(Ci.nsIProperties)
  549.                        .get("ProfD", Ci.nsIFile);
  550.   relicBlogFile.append(OLD_BLOG_RDF_FILE_RELIC);
  551.  
  552.   // only migrate if the old favorites rdf file exists
  553.   // FIXME: after the flock_favorites.rdf file is renamed to flock_favorites_old.rdf
  554.   // flock_favorites.rdf is created again in the same dir. so we need the 2nd
  555.   // condition in the IF to stop migration from happening again
  556.   if(oldBlogFile.exists() && !relicBlogFile.exists()) {
  557.     return true;
  558.   }
  559.   return false;
  560. }
  561.  
  562. flockBlogService.prototype.startMigration = 
  563. function(oldVersion, aFlockMigrationProgressListener)
  564. {
  565.   this.init();
  566.  
  567.   var shelf_svc = Cc['@mozilla.org/rdf/datasource;1?name=flock-shelf'].getService(Ci.flockIShelfService);
  568.  
  569.   var oldShelfFile = Cc["@mozilla.org/file/directory_service;1"] 
  570.                        .getService(Ci.nsIProperties)
  571.                        .get("ProfD", Ci.nsIFile);
  572.   oldShelfFile.append(OLD_SHELF_RDF_FILE);
  573.  
  574.   var oldBlogFile = Cc["@mozilla.org/file/directory_service;1"] 
  575.                        .getService(Ci.nsIProperties)
  576.                        .get("ProfD", Ci.nsIFile);
  577.   oldBlogFile.append(OLD_BLOG_RDF_FILE);
  578.  
  579.   var relicBlogFile = Cc["@mozilla.org/file/directory_service;1"] 
  580.                        .getService(Ci.nsIProperties)
  581.                        .get("ProfD", Ci.nsIFile);
  582.   relicBlogFile.append(OLD_BLOG_RDF_FILE_RELIC);
  583.  
  584.   var ctxt = {
  585.     listener: aFlockMigrationProgressListener,
  586.     oldShelfFile: oldShelfFile,
  587.     oldBlogFile: oldBlogFile
  588.   };
  589.  
  590.   if (oldBlogFile.exists())
  591.     ctxt.listener.onUpdate(0, 'Migrating blog settings');
  592.  
  593.   return { wrappedJSObject: ctxt };
  594. }
  595.  
  596. flockBlogService.prototype.finishMigration = 
  597. function(ctxtWrapper)
  598. {
  599. }
  600.  
  601. flockBlogService.prototype.doMigrationWork =
  602. function(ctxtWrapper)
  603. {
  604.   var ctxt = ctxtWrapper.wrappedJSObject;
  605.  
  606.   if (!ctxt.oldBlogFile.exists())
  607.     return false;
  608.  
  609.   if (!ctxt.blogMigrator)
  610.     ctxt.blogMigrator = this._migrateBlogs(ctxt);
  611.   if (ctxt.blogMigrator.next())
  612.     ctxt.blogMigrator = null;
  613.  
  614.   return Boolean(ctxt.blogMigrator);
  615. }
  616.  
  617. flockBlogService.prototype._migrateBlogs =
  618. function(ctxt)
  619. {
  620.   var blogsvc = this;
  621.   var acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  622.  
  623.   function createAccountAndBlog (aServiceId, aServiceUrn, aUsername, aPassword, aBlogName, aBlogid, aUrl, aApilink) {
  624.     var svc = Cc[aServiceId].getService(Ci.flockIWebService);
  625.     svc.init();
  626.     acUtils.setPassword(svc.urn+":"+aUsername, aUsername, aPassword);
  627.  
  628.     var accountURN = svc.urn+":"+aUsername;
  629.     var account = new blogsvc._coop.Account(accountURN, {
  630.       name: aUsername,
  631.       serviceId: aServiceId,
  632.       service: blogsvc._coop.get(aServiceUrn),
  633.       accountId: aUsername,
  634.       favicon: svc.icon,
  635.       URL: svc.url
  636.     });
  637.     blogsvc._coop.accounts_root.children.addOnce(account);
  638.  
  639.     var theCoopBlog = new blogsvc._coop.Blog(accountURN+":"+aBlogid, {
  640.       name: aBlogName,
  641.       title: aBlogName,
  642.       blogid: aBlogid,
  643.       URL: aUrl,
  644.       apiLink: aApilink
  645.     });
  646.     account.children.addOnce(theCoopBlog);
  647.   }
  648.  
  649.   var rdfs = Cc["@mozilla.org/rdf/rdf-service;1"].getService (Ci.nsIRDFService);
  650.   var ios = Cc['@mozilla.org/network/io-service;1'].getService (Ci.nsIIOService);
  651.   var ds = rdfs.GetDataSourceBlocking(ios.newFileURI(ctxt.oldBlogFile).spec);
  652.  
  653.   var accountsRes = rdfs.GetResource("urn:flock:blog:settings");
  654.   var container = Cc["@mozilla.org/rdf/container;1"].createInstance(Ci.nsIRDFContainer);
  655.   container.Init(ds, accountsRes);
  656.  
  657.   var children = container.GetElements();
  658.   this.logger.info("Start migration of the blog accounts");
  659.   while (children.hasMoreElements()){
  660.     var child = children.getNext().QueryInterface(Ci.nsIRDFResource);
  661.     var apiRes = rdfs.GetResource(child.ValueUTF8 + ":api");
  662.  
  663.     var nameRes = rdfs.GetResource("http://www.flock.com/rdf#title");
  664.     var name = ds.GetTarget(child, nameRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  665.  
  666.     this.logger.info("Found the blog: "+name+" for import");
  667.     ctxt.listener.onUpdate(0, "Migrating " + name);
  668.     yield false;
  669.  
  670.     var urlRes = rdfs.GetResource("http://www.flock.com/rdf#url");
  671.     var url = ds.GetTarget(child, urlRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  672.  
  673.     var blogidRes = rdfs.GetResource("http://www.flock.com/rdf#blogid");
  674.     var blogid = ds.GetTarget(apiRes, blogidRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  675.  
  676.     var apilinkRes = rdfs.GetResource("http://www.flock.com/rdf#apiLink");
  677.     var apilink = ds.GetTarget(apiRes, apilinkRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  678.  
  679.     // Get the username/password...
  680.     var usernameRes = rdfs.GetResource("http://www.flock.com/rdf#username");
  681.     var username = ds.GetTarget(child, usernameRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  682.     var password = "";
  683.     this.logger.info("    Username = "+username);
  684.     if (username != "") {
  685.       var pwhostRes = rdfs.GetResource("http://www.flock.com/rdf#pwhost");
  686.       var pwhost = ds.GetTarget(child, pwhostRes, true).QueryInterface(Ci.nsIRDFLiteral).Value;
  687.  
  688.       var password = getPassword(pwhost, username)
  689.     }
  690.     if (password == null || password == "") {
  691.       // The password was not stored or we couldn't find it
  692.       this.logger.info("    The password seems to be empty/unknown, let's ask the user");
  693.       var promptService = Cc['@mozilla.org/embedcomp/prompt-service;1'].getService(Ci.nsIPromptService);
  694.       var winMediator = Cc['@mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator);
  695.  
  696.       var theUsername = {value: username};
  697.       var thePassword = {value: password};
  698.       promptService.promptUsernameAndPassword (
  699.           winMediator.getMostRecentWindow('navigator:browser'),
  700.           "Blog Account Import",
  701.           "Please enter your login information for "+name+"\n("+url+")",
  702.           theUsername, thePassword,
  703.           null, {value: false}
  704.       );
  705.       username = theUsername.value;
  706.       password = thePassword.value;
  707.     }
  708.     this.logger.info("   We finally have "+username+" and "+password);
  709.  
  710.     // The user pressed cancel or gave a blank password => don't add the blog
  711.     if (password == null || password == "")
  712.       break;
  713.     
  714.     // Now we can create the blog
  715.     if (url.match(/wordpress\.com/)) {
  716.       createAccountAndBlog ('@flock.com/people/wordpress;1', 'urn:wordpress:service', username, password,
  717.                             name, blogid, url, apilink);
  718.     }
  719.     else if (url.match(/livejournal\.com/)) {
  720.       apilink = 'http://www.livejournal.com/interface/xmlrpc';
  721.       createAccountAndBlog ('@flock.com/people/livejournal;1', 'urn:livejournal:service', username, password,
  722.                             name, blogid, url, apilink);
  723.     }
  724.     else if (url.match(/blogspot\.com/)) {
  725.       createAccountAndBlog ('@flock.com/people/blogger;1', 'urn:blogger:service', username, password,
  726.                             name, name, url, apilink);
  727.     }
  728.     else if (url.match(/typepad\.com/)) {
  729.       createAccountAndBlog ('@flock.com/blog/typepad;1', 'urn:typepad:service', username, password,
  730.                             name, blogid, url, apilink);
  731.     }
  732.     else { // Custom blog
  733.       try {
  734.         var apiRes = rdfs.GetResource("http://www.flock.com/rdf#api");
  735.         var api = ds.GetTarget(child, apiRes, true).QueryInterface(Ci.nsIRDFResource);
  736.         var apinameRes = rdfs.GetResource("http://www.flock.com/rdf#apiname");
  737.         var apiname = ds.GetTarget(api, apinameRes, true).QueryInterface(Ci.nsIRDFLiteral);
  738.         var blogidRes = rdfs.GetResource("http://www.flock.com/rdf#blogid");
  739.         var blogid = ds.GetTarget(api, blogidRes, true).QueryInterface(Ci.nsIRDFLiteral);
  740.         var apiLinkRes = rdfs.GetResource("http://www.flock.com/rdf#apiLink");
  741.         var apiLink = ds.GetTarget(api, apiLinkRes, true).QueryInterface(Ci.nsIRDFLiteral);
  742.  
  743.         // Create a custom account...
  744.         var customURN = "urn:flock:customblog:"+name;
  745.         if (!this._coop.Account.exists (customURN)) {
  746.           var custom = new this._coop.Account(customURN, {
  747.             name : name,
  748.             accountId : username,
  749.             serviceId: '@flock.com/blog/service/'+apiname.Value+';1',
  750.             URL : url,
  751.             favicon: 'http://'+url.split('/')[2]+'/favicon.ico'
  752.           });
  753.           var root = this._coop.get("http://flock.com/rdf#AccountsRoot");
  754.           root.children.add(custom);
  755.         }
  756.  
  757.         // ...save the password in the password manager...
  758.         var blogURN = customURN+":"+name;
  759.         var acUtils = Cc["@flock.com/account-utils;1"].getService(Ci.flockIAccountUtils);
  760.         acUtils.setPassword(customURN, username, password);
  761.         // ...and create a new blog as a child
  762.         theCoopBlog = new this._coop.Blog(blogURN, {
  763.           name: name,
  764.           title: name,
  765.           blogid: blogid.Value,
  766.           URL: url,
  767.           apiLink: apiLink.Value,
  768.         });
  769.         custom.children.addOnce(theCoopBlog);
  770.       }
  771.       catch(e) {
  772.         debug(e);
  773.       }
  774.     }
  775.   }
  776.  
  777.   // Import web snippets (shelf)
  778.   // debug("Import web snippets\n");
  779.   var shelf_svc = Cc['@mozilla.org/rdf/datasource;1?name=flock-shelf'].getService(Ci.flockIShelfService);
  780.   var shelfDS = rdfs.GetDataSourceBlocking(ios.newFileURI(ctxt.oldShelfFile).spec);
  781.   var shelfRes = rdfs.GetResource("urn:flock:shelf:objects");
  782.   var container = Cc["@mozilla.org/rdf/container;1"].createInstance(Ci.nsIRDFContainer);
  783.   container.Init(shelfDS, shelfRes);
  784.  
  785.   var importFolderId;
  786.   var children = container.GetElements();
  787.   while (children.hasMoreElements()){
  788.     var child = children.getNext().QueryInterface(Ci.nsIRDFResource);
  789.  
  790.     var nameRes = rdfs.GetResource("http://www.flock.com/rdf/shelf#title");
  791.     var name = shelfDS.GetTarget(child, nameRes, true).QueryInterface(Ci.nsIRDFLiteral);
  792.  
  793.     var contentRes = rdfs.GetResource("http://www.flock.com/rdf/shelf#content");
  794.     var content = shelfDS.GetTarget(child, contentRes, true).QueryInterface(Ci.nsIRDFLiteral);
  795.  
  796.     var urlRes = rdfs.GetResource("http://www.flock.com/rdf/shelf#url");
  797.     var url = shelfDS.GetTarget(child, urlRes, true).QueryInterface(Ci.nsIRDFLiteral);
  798.  
  799.     var typeRes = rdfs.GetResource("http://www.flock.com/rdf/shelf#type");
  800.     var type = shelfDS.GetTarget(child, typeRes, true).QueryInterface(Ci.nsIRDFLiteral);
  801.     var myType;
  802.     if (type.Value == "note") {
  803.       // The "note" type is deprecated
  804.       myType = "document";
  805.     } else {
  806.       myType = type.Value;
  807.     }
  808.  
  809.     debug(importFolderId+"\n");
  810.     ctxt.listener.onUpdate(0, 'Importing clipping: ' + name.Value);
  811.     shelf_svc.insert(name.Value, content.Value, url.Value, myType, -1, null);
  812.   }
  813.   // debug("Done with 'Import web snippets'\n");
  814.  
  815.   // Import blog posts
  816.   var prefs = Cc["@mozilla.org/preferences-service;1"]
  817.               .getService(Ci.nsIPrefService)
  818.               .getBranch("flock.blog.");
  819.   var init_dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  820.  
  821.   try {
  822.     var value = prefs.getComplexValue("saveLocation", Ci.nsISupportsString).data;
  823.   } catch(e) {}
  824.  
  825.     if (value) {
  826.  
  827.     init_dir.initWithPath(value);
  828.     var importDraftsFolderId;
  829.     var enum = init_dir.directoryEntries;
  830.     while (enum.hasMoreElements()) {
  831.       var file = enum.getNext().QueryInterface(Ci.nsILocalFile);
  832.  
  833.       try {
  834.         // Get the content of the file
  835.         var instream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);    
  836.         var scriptinstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
  837.         instream.init(file, 0x01, 00400 | 00200 | 00040 | 00004, 0);
  838.         scriptinstream.init(instream);
  839.         var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
  840.         converter.charset = "UTF-8";
  841.         var result = scriptinstream.read(scriptinstream.available());
  842.         var finalresult; // Mark is getting an exception around here
  843.         finalresult = converter.ConvertToUnicode(result);
  844.         finalresult += converter.Finish();
  845.         scriptinstream.close();
  846.  
  847.         // Separate the title from the content
  848.         var theTitle = finalresult.substring(0, finalresult.indexOf('\n'));
  849.         theTitle = theTitle.replace(/<h1>/, '').replace(/<\/h1>/, '');
  850.         var theBody = finalresult.substring(finalresult.indexOf('\n')+1, finalresult.length);
  851.  
  852.         // Add to the drafts
  853.         var newId = this.saveDraft(null, theTitle, theBody, "");
  854.         this.moveTo(newId, "imported");
  855.       }
  856.       catch(e) {
  857.         // TODO: give feedback to the user, saying we failed to import one draft
  858.         debug("**** Error while importing the blog draft: "+file.path+". I will just ignore this draft and go on.\n\n"+e+"\n");
  859.       }
  860.     }
  861.   }
  862.  
  863.   // Set this pref to prevent 0.9.0 => 0.9.1 migration to happen
  864.   prefs.setBoolPref("mozstorage", true);
  865.  
  866.   // rename the file and delete the old copy
  867.   rdfs.UnregisterDataSource(ds);
  868.   ds = null;
  869.   
  870.   ctxt.oldBlogFile.moveTo(null, OLD_BLOG_RDF_FILE_RELIC);
  871.   yield true;
  872. }
  873.  
  874. // nsIObserver
  875. flockBlogService.prototype.observe =
  876. function(subject, topic, state)
  877. {
  878.   switch (topic) {
  879.     case 'flock-data-ready':
  880.       var obs = Cc["@mozilla.org/observer-service;1"]
  881.         .getService(Ci.nsIObserverService);
  882.       obs.removeObserver(this, 'flock-data-ready');
  883.       this.init();
  884.       return;
  885.   }
  886. }
  887.  
  888.  
  889. // nsISimpleEnumerator implementation
  890. function simpleEnumerator (aArray)
  891. {
  892.   aArray.hasMoreElements = function () { 
  893.     return this.length != 0; 
  894.   }
  895.   aArray.getNext = function () { 
  896.     var rval = this.shift (); 
  897.     return rval;
  898.   }
  899.   return aArray;
  900. }
  901.  
  902. // nsIStringEnumerator implementation
  903. function stringEnumerator (aArray)
  904. {
  905.   aArray.hasMore = function () { 
  906.     return this.length != 0; 
  907.   }
  908.   aArray.getNext = function () { 
  909.     var rval = this.shift (); 
  910.     return rval;
  911.   }
  912.   return aArray;
  913. }
  914.  
  915. loadLibraryFromSpec('chrome://browser/content/flock/contrib/rdfds.js');
  916.  
  917. function loadLibraryFromSpec(aSpec)
  918. {
  919.   var loader = Cc['@mozilla.org/moz/jssubscript-loader;1']
  920.     .getService(Ci.mozIJSSubScriptLoader);
  921.  
  922.   loader.loadSubScript(aSpec);
  923. }
  924.  
  925.  
  926. function getPassword(aHost, aUsername)
  927. {
  928.   var psm = Cc["@mozilla.org/passwordmanager;1"].getService(Ci.nsIPasswordManager);
  929.   var enum = psm.enumerator;
  930.   while(enum.hasMoreElements()) {
  931.     var pw = enum.getNext();
  932.     pw = pw.QueryInterface(Ci.nsIPassword);
  933.     if(pw.host==aHost && aUsername==pw.user) {
  934.       return pw.password;
  935.     }
  936.   }
  937.   return null;
  938. }
  939.  
  940. // Ensure that the "recent" list as no more than BLOG_RECENT_COUNT elements
  941. flockBlogService.prototype.cleanRecent = function () {
  942.   debug("*** flockBlogService.cleanRecent: NOT IMPLEMENTED. DO IT NOW!! ***\n");
  943. }
  944.  
  945. // the flockIBlogService implementation
  946.  
  947. flockBlogService.prototype.accountExists = function (aTitle) { 
  948.   var accounts = this._coop.Blog.find({ title: aTitle });
  949.   return (accounts.length > 0); 
  950. }
  951.  
  952.  
  953. flockBlogService.prototype.accountCount = function () {
  954.   var count = 0;
  955.   var accounts = this._coop.get('http://flock.com/rdf#AccountsRoot');
  956.   var enum = accounts.children.enumerate();
  957.   while (enum.hasMoreElements()) {
  958.     var account = enum.getNext();
  959.     if (!account) continue; // getNext() can return NULL when hasMoreElements() is TRUE.
  960.     var enum2 = account.children.enumerate();
  961.     while (enum2.hasMoreElements())
  962.       if (enum2.getNext().isInstanceOf(this._coop.Blog))
  963.         ++count;
  964.   }
  965.   return count;
  966. }
  967.  
  968.  
  969. flockBlogService.prototype.getAccountList = function () {
  970.   var result = new Array();
  971.  
  972.   var accounts = this._coop.get('http://flock.com/rdf#AccountsRoot');
  973.   var enum = accounts.children.enumerate();
  974.   while (enum.hasMoreElements()) {
  975.     var account = enum.getNext();
  976.     if (!account) continue; // getNext() can return NULL when hasMoreElements() is TRUE.
  977.     var enum2 = account.children.enumerate();
  978.     while (enum2.hasMoreElements()) {
  979.       var child = enum2.getNext();
  980.       if (child.isInstanceOf(this._coop.Blog))
  981.         result.push(child);
  982.     }
  983.   }
  984.  
  985.   return simpleEnumerator(result);
  986. }
  987.  
  988.  
  989. flockBlogService.prototype.getDefaultBlog = function () { 
  990.   var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  991.                 .getService(Components.interfaces.nsIPrefService)
  992.                 .getBranch("flock.blog.");
  993.   var value = null;
  994.   try{
  995.     value = prefs.getCharPref ("defaultblog");
  996.   } catch(e) {
  997.     return "";
  998.   }
  999.   return value;
  1000. }
  1001.  
  1002.  
  1003. flockBlogService.prototype.setDefaultBlog = function (aValue) { 
  1004.   var prefs = Components.classes["@mozilla.org/preferences-service;1"]
  1005.                 .getService(Components.interfaces.nsIPrefService)
  1006.                 .getBranch("flock.blog.");
  1007.   prefs.setCharPref ("defaultblog", aValue);
  1008. }
  1009.  
  1010.  
  1011.  
  1012. flockBlogService.prototype.addRecent = function (aName, aFile) { 
  1013.   debug("*** flockBlogService.addRecent: NOT IMPLEMENTED. DO IT NOW!! ***\n");
  1014. }
  1015.  
  1016.  
  1017. flockBlogService.prototype.recentIsEmpty =
  1018. function ()
  1019.   debug("*** flockBlogService.recentIsEmpty: NOT IMPLEMENTED. DO IT NOW!! ***\n");
  1020. }
  1021.  
  1022.  
  1023. flockBlogService.prototype.registerAPI =
  1024. function(aService, aShortname)
  1025. {
  1026.   this.mName2ServiceMap[aShortname] = aService;
  1027.   this.mService2NameMap[aService] = aShortname;
  1028. }
  1029.  
  1030.  
  1031. flockBlogService.prototype.getAPIFromShortname =
  1032. function(aShortname)
  1033. {
  1034.   for (i in this.mName2ServiceMap) {
  1035.     debug(i+": "+this.mName2ServiceMap[i]+"\n");
  1036.   }
  1037.   return this.mName2ServiceMap[aShortname];
  1038. }
  1039.  
  1040.  
  1041. flockBlogService.prototype.getShortnameFromAPI =
  1042. function(aService)
  1043. {
  1044.   return this.mService2NameMap[aService];
  1045. }
  1046.  
  1047.  
  1048. flockBlogService.prototype.__defineGetter__('services', function ()
  1049. {
  1050.   var ar = new Array();
  1051.   for(var p in this.mName2ServiceMap) {
  1052.     ar.push(this.mName2ServiceMap[p]);
  1053.   }
  1054.   var rval = {
  1055.     getNext: function() {
  1056.       var rval = ar.shift();
  1057.       return rval;
  1058.     },
  1059.     hasMoreElements: function() {
  1060.       return (ar.length>0);
  1061.     },
  1062.   }
  1063.   return rval;
  1064. })
  1065.  
  1066.  
  1067. flockBlogService.prototype.getCandidatesAPI =
  1068. function(aListener, aUrl)
  1069. {
  1070.   var detector = new BlogAPIDetector();
  1071.   detector.detect(aListener, aUrl);
  1072. }
  1073.  
  1074.  
  1075. flockBlogService.prototype.saveAccount =
  1076. function (aParentId, aId, aBlogAccount)
  1077. {
  1078.   // Get or create the coop object
  1079.   var account = null;
  1080.   if (aId) {
  1081.     account = this._coop.get(aId);
  1082.     if (!account)
  1083.       account = new this._coop.Blog(aId);
  1084.   }
  1085.   else
  1086.     account = new this._coop.Blog(aParentId+":"+aBlogAccount.username);
  1087.  
  1088.   // Save the password in the password manager
  1089.   var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
  1090.   var uri = ios.newURI(aBlogAccount.URL, null, null);
  1091.   var pwhost = "flockinternal." + uri.host;
  1092.   if(aBlogAccount.username && aBlogAccount.username.length) {
  1093.     var psm = Cc["@mozilla.org/passwordmanager;1"].getService(Ci.nsIPasswordManager);
  1094.     psm.addUser(pwhost, aBlogAccount.username, aBlogAccount.password);
  1095.   }
  1096.  
  1097.   // Save the rest in flock-data
  1098.   account.title = aBlogAccount.title;
  1099.   account.name = aBlogAccount.title;
  1100.   account.favicon = aBlogAccount.favicon;
  1101.   account.username = aBlogAccount.username;
  1102.   account.URL = aBlogAccount.URL;
  1103.   account.pwhost = pwhost;
  1104.   account.api = aBlogAccount.api;
  1105.   account.apiLink = aBlogAccount.apiLink;
  1106.   account.blogid = aBlogAccount.blogid;
  1107.   account.authtoken = aBlogAccount.authtoken;
  1108.  
  1109.   var parent = this._coop.get(aParentId);
  1110.   parent.children.add(account);
  1111. }
  1112.  
  1113. flockBlogService.prototype.getAccount = function (aBlogID) {
  1114.   if(!aBlogID) throw new Error("Error in BlogSettings.getAccount()");
  1115.   var coopblog = this._coop.get(aBlogID);
  1116.   var coopaccount = coopblog.getParent();
  1117.  
  1118.   if (coopaccount) {
  1119.     // var password = getPassword(coopaccount.id()+":"+coopaccount.accountId, coopaccount.accountId);
  1120.     debug(" ^^^^^^^^^ Get the password for "+coopaccount.id()+"\n");
  1121.     var pw = this.acUtils.getPassword(coopaccount.id());
  1122.     if (pw)
  1123.       var password = pw.password;
  1124.     debug("++++++ Found the password: "+password+"\n");
  1125.   }
  1126.  
  1127.   var account = {
  1128.     blogid: coopblog.blogid,
  1129.     username: coopaccount.accountId,
  1130.     password: password,
  1131.     authtoken: coopblog.authtoken,
  1132.     apiLink: coopblog.apiLink,
  1133.     getInterfaces: function (count) {
  1134.       var interfaceList = [Ci.flockIBlogAccount, Ci.nsIClassInfo];
  1135.       count.value = interfaceList.length;
  1136.       return interfaceList;
  1137.     },
  1138.     QueryInterface: function (iid) {
  1139.       if (!iid.equals(Ci.flockIBlogAccount))
  1140.         throw Cr.NS_ERROR_NO_INTERFACE;
  1141.       return this;
  1142.     }
  1143.   }
  1144.  
  1145.   return account;
  1146. };
  1147.  
  1148.  
  1149. flockBlogService.prototype.getBlogAPI = function (aBlogID) {
  1150.   try {
  1151.     var account = this._coop.get(aBlogID);
  1152.  
  1153.     return this.getAPIFromShortname(account.api);
  1154.   }
  1155.   catch(e) {
  1156.     debug("Caught exception: "+e+" "+e.fileName+" "+e.lineNumber+"\n");
  1157.     return null;
  1158.   }
  1159. };
  1160.  
  1161. flockBlogService.prototype.addCategory = function (aBlogID, aCategoryId, aCategoryName) {
  1162.   var account = this._coop.get(aBlogID);
  1163.   var enum = account.categories.enumerate();
  1164.   var category = null;
  1165.   while (enum.hasMoreElements()) {
  1166.     var cat = enum.getNext();
  1167.     if (cat.categoryId == aCategoryId)
  1168.       category = cat;
  1169.   }
  1170.   if (!category) {
  1171.     category = new this._coop.BlogCategory();
  1172.     category.categoryId = aCategoryId;
  1173.   }
  1174.   category.name = aCategoryName;
  1175.  
  1176.   account.categories.addOnce(category);
  1177. };
  1178.  
  1179. flockBlogService.prototype.flushCategories = function (aBlogAccount) {
  1180.   debug("*** flockBlogService.flushCategories: DEPRECATED. DON'T USE IT!! ***\n");
  1181. };
  1182.  
  1183. flockBlogService.prototype.addNotification = function (aURL) {
  1184.   debug("*** flockBlogService.addNotification: NOT IMPLEMENTED. DO IT NOW!! ***\n");
  1185. };
  1186.  
  1187. flockBlogService.prototype.removeNotification = function (aURL) {
  1188.   debug("*** flockBlogService.removeNotification: NOT IMPLEMENTED. DO IT NOW!! ***\n");
  1189. };
  1190.  
  1191.  
  1192. flockBlogService.prototype.getNotifications = function () {
  1193.   debug("*** flockBlogService.getNotifications: NOT IMPLEMENTED. DO IT NOW!! ***\n");
  1194.   return stringEnumerator([]);
  1195. };
  1196.  
  1197.  
  1198. flockBlogService.prototype._openBlogEditor =
  1199. function (aParams) {
  1200.   // Recover if needed
  1201.   var needRecovery = false;
  1202.   if (!this.editorIsOpen()) {
  1203.     var _enum = this.getAllRecovery();
  1204.     if (_enum.hasMoreElements()) // There is at least one recovered draft
  1205.       needRecovery = true;
  1206.   }
  1207.  
  1208.   if (needRecovery) {
  1209.     var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  1210.     var win = wm.getMostRecentWindow('navigator:browser');
  1211.     win.openDialog("chrome://flock/content/blog/blogRecovery.xul",
  1212.                    "openRecovery", "chrome,modal,centerscreen", null);
  1213.   }
  1214.   var ww = Cc['@mozilla.org/embedcomp/window-watcher;1'].getService(Ci.nsIWindowWatcher);
  1215.   return ww.openWindow(null, EDITOR_URL, "_blank", "chrome,close,titlebar,resizable=yes,toolbar=no,dialog=no,scrollbars=yes", aParams);
  1216. }
  1217.  
  1218.  
  1219. flockBlogService.prototype.openPost =
  1220. function (aId) {
  1221.   var windowMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  1222.     .getService(Components.interfaces.nsIWindowMediator);
  1223.  
  1224.   // See if the post is not already open
  1225.   var oldWin = null;
  1226.   
  1227.   var singleUploadWindow = false;
  1228.   var allWindows = windowMediator.getEnumerator(null);
  1229.   debug("Looking for {"+aId+"}\n");
  1230.   while (allWindows.hasMoreElements() && !oldWin) {
  1231.     var win = allWindows.getNext();
  1232.     if (win.gDraftId && (win.gDraftId == aId)) {
  1233.       oldWin = win;
  1234.     }
  1235.   }
  1236.  
  1237.   if (oldWin) { // Bring the existing window to the front
  1238.     oldWin.focus();
  1239.   }
  1240.   else { // Open a new window
  1241.     var params = Cc["@mozilla.org/embedcomp/dialogparam;1"].createInstance(Ci.nsIDialogParamBlock);
  1242.     params.SetNumberStrings(4);
  1243.     params.SetString(0, aId);
  1244.     params.SetString(1, "");
  1245.     params.SetString(2, "");
  1246.     params.SetString(3, "");
  1247.  
  1248.     this._openBlogEditor(params);
  1249.   }
  1250. }
  1251.  
  1252.  
  1253. flockBlogService.prototype.openEditor =
  1254. function (aTitle, aContent, aTags) {
  1255.   var setup = 1; // Default to "Cancel"
  1256.  
  1257.   if (this.accountCount() == 0) {
  1258.     // Tell the user to configure an account
  1259.     var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  1260.     var win = wm.getMostRecentWindow('navigator:browser');
  1261.     var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"]
  1262.              .getService(Ci.nsIPromptService);
  1263.     var sbs = Cc["@mozilla.org/intl/stringbundle;1"]
  1264.               .getService(Ci.nsIStringBundleService);
  1265.     var sb = sbs.createBundle("chrome://flock/locale/blog/blog.properties");
  1266.     var brand = sbs.createBundle("chrome://branding/locale/brand.properties");
  1267.  
  1268.     var flags = Ci.nsIPromptService.BUTTON_TITLE_IS_STRING *
  1269.                 Ci.nsIPromptService.BUTTON_POS_0 +
  1270.                 Ci.nsIPromptService.BUTTON_TITLE_CANCEL *
  1271.                 Ci.nsIPromptService.BUTTON_POS_1 +
  1272.                 Ci.nsIPromptService.BUTTON_TITLE_IS_STRING *
  1273.                 Ci.nsIPromptService.BUTTON_POS_2;
  1274.  
  1275.     var title = sb.GetStringFromName("flock.blog.account.req.title");
  1276.     var button1 = sb.GetStringFromName("flock.blog.account.req.setupButton");
  1277.     var appName = brand.GetStringFromName("brandShortName");
  1278.     var button3 = sb.GetStringFromName("flock.blog.account.req.continueButton");
  1279.     var substitutions = [button1, appName, button3];
  1280.     var bodyText = sb.formatStringFromName("flock.blog.account.req.text",
  1281.                                            substitutions,
  1282.                                            substitutions.length);
  1283.  
  1284.     setup = ps.confirmEx(win,
  1285.                          title,
  1286.                          bodyText,
  1287.                          flags,
  1288.                          button1,
  1289.                          null,
  1290.                          button3,
  1291.                          null,
  1292.                          {});
  1293.   }
  1294.   else {
  1295.     setup = 2;
  1296.   }
  1297.  
  1298.   switch (setup) {
  1299.   case 0:
  1300.     // "Setup Account"
  1301.     win.flock_blogLaunchSettings();
  1302.     break;
  1303.   case 2:
  1304.     // "Continue"
  1305.     //dump("aContent = "+aContent+"\n");
  1306.     var params = Cc["@mozilla.org/embedcomp/dialogparam;1"].createInstance(Ci.nsIDialogParamBlock);
  1307.     params.SetNumberStrings(4);
  1308.     params.SetString(0, "");
  1309.     params.SetString(1, aTitle?aTitle:"");
  1310.     params.SetString(2, aContent?aContent:"");
  1311.     params.SetString(3, aTags?aTags:"");
  1312.     return this._openBlogEditor(params);
  1313.   default:
  1314.     // Cancel
  1315.   }
  1316.   return null;
  1317. }
  1318.  
  1319.  
  1320. flockBlogService.prototype.editorIsOpen =
  1321. function () {
  1322.   var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  1323.   return (!!wm.getMostRecentWindow("Flock:BlogEditor"));
  1324. }
  1325.  
  1326. flockBlogService.prototype._save =
  1327. function (aId, aTitle, aContent, aTags, aRecovery) {
  1328.   var now = (new Date()).getTime();
  1329.   var id = (aId && aId > 0)?aId:(now * 100 + Math.floor(Math.random() * 100));
  1330.  
  1331.   if (aRecovery) {
  1332.     gBlogStorage.saveRecovery(id, now, aTitle, aContent, aTags);
  1333.   } else {
  1334.     gBlogStorage.saveDraft(id, now, aTitle, aContent, aTags);
  1335.   }
  1336.   return id;
  1337. }
  1338.  
  1339. flockBlogService.prototype.saveDraft =
  1340. function (aId, aTitle, aContent, aTags) {
  1341.   return this._save(aId, aTitle, aContent, aTags, false);
  1342. }
  1343.  
  1344. flockBlogService.prototype.saveRecovery =
  1345. function (aId, aTitle, aContent, aTags) {
  1346.   return this._save(aId, aTitle, aContent, aTags, true);
  1347. }
  1348.  
  1349. flockBlogService.prototype.getDraft =
  1350. function flockBlogService_getDraft (aDraftId) {
  1351.   return gBlogStorage.getDraft(aDraftId);
  1352. }
  1353.  
  1354. flockBlogService.prototype.getDraftsFrom =
  1355. function flockBlogService_getDraftsFrom (aBlogId) {
  1356.   var drafts = gBlogStorage.getDraftsFrom (aBlogId);
  1357.   return simpleEnumerator(drafts);
  1358. }
  1359.  
  1360. flockBlogService.prototype.moveTo =
  1361. function flockBlogService_moveTo (aId, aBlogId) {
  1362.   gBlogStorage.setDraftBlog(aId, aBlogId);
  1363. }
  1364.  
  1365.  
  1366. flockBlogService.prototype.removeDraft =
  1367. function (aId) {
  1368.   gBlogStorage.deleteDraft(aId);
  1369. }
  1370.  
  1371.  
  1372. flockBlogService.prototype.removeRecovery =
  1373. function (aId) {
  1374.   gBlogStorage.deleteRecovery(aId);
  1375. }
  1376.  
  1377.  
  1378. flockBlogService.prototype.looseRecovery =
  1379. function () {
  1380.   gBlogStorage.emptyRecovery();
  1381. }
  1382.  
  1383. flockBlogService.prototype.getAllRecovery =
  1384. function flockBlogService_getAllRecovery () {
  1385.   var recoveries = gBlogStorage.getAllRecovery ();
  1386.   return simpleEnumerator(recoveries);
  1387. }
  1388.  
  1389.  
  1390. flockBlogService.prototype.flags = Ci.nsIClassInfo.SINGLETON;
  1391. flockBlogService.prototype.classDescription = "Flock Blog Service";
  1392. flockBlogService.prototype.getInterfaces = function (count) {
  1393.     var interfaceList = [Ci.flockIBlogService, Ci.flockIMigratable,
  1394.                          Ci.nsIObserver, Ci.nsIClassInfo];
  1395.     count.value = interfaceList.length;
  1396.     return interfaceList;
  1397. }
  1398. flockBlogService.prototype.getHelperForLanguage = function (count) {return null;}
  1399.  
  1400. // the nsISupports implementation
  1401. flockBlogService.prototype.QueryInterface =
  1402. function (iid) {
  1403.     if (!iid.equals(Ci.flockIBlogService) && 
  1404.         !iid.equals(Ci.flockIMigratable) &&
  1405.         !iid.equals(Ci.nsIClassInfo) &&
  1406.         !iid.equals(Ci.nsIObserver) &&
  1407.         !iid.equals(Ci.nsISupports))
  1408.         throw Cr.NS_ERROR_NO_INTERFACE;
  1409.     return this;
  1410. }
  1411.  
  1412. // Module implementation
  1413. var BlogModule = new Object();
  1414.  
  1415. BlogModule.registerSelf =
  1416. function (compMgr, fileSpec, location, type)
  1417. {
  1418.     compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  1419.  
  1420.     compMgr.registerFactoryLocation(FLOCK_BLOG_CID, 
  1421.                                     "Flock Blog JS Component",
  1422.                                     FLOCK_BLOG_CONTRACTID, 
  1423.                                     fileSpec, 
  1424.                                     location,
  1425.                                     type);
  1426.  
  1427.     // Make the blog service a startup observer (for migration)
  1428.     var categoryManager = Cc["@mozilla.org/categorymanager;1"]
  1429.       .getService(Ci.nsICategoryManager);
  1430.     categoryManager.addCategoryEntry("flock-startup", "Flock Blog Service", "service," + FLOCK_BLOG_CONTRACTID, true, true);
  1431.     categoryManager.addCategoryEntry('flockMigratable', 'blogservice', FLOCK_BLOG_CONTRACTID, true, true);
  1432. }
  1433.  
  1434. BlogModule.getClassObject =
  1435. function (compMgr, cid, iid) {
  1436.     if (!cid.equals(FLOCK_BLOG_CID))
  1437.         throw Cr.NS_ERROR_NO_INTERFACE;
  1438.     
  1439.     if (!iid.equals(Ci.nsIFactory))
  1440.         throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  1441.     
  1442.     return BlogServiceFactory;
  1443. }
  1444.  
  1445. BlogModule.canUnload =
  1446. function(compMgr)
  1447. {
  1448.     return true;
  1449. }
  1450.     
  1451. /* factory object */
  1452. var BlogServiceFactory = new Object();
  1453.  
  1454. BlogServiceFactory.createInstance =
  1455. function (outer, iid) {
  1456.     if (outer != null)
  1457.         throw Cr.NS_ERROR_NO_AGGREGATION;
  1458.  
  1459.     return (new flockBlogService()).QueryInterface(iid);
  1460. }
  1461.  
  1462. /* entrypoint */
  1463. function NSGetModule(compMgr, fileSpec) {
  1464.     return BlogModule;
  1465. }
  1466.